package com.code9xs.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.code9xs.mapper.*;
import com.code9xs.pojo.*;
import com.code9xs.service.ArticleService;
import com.code9xs.service.AssociationService;
import com.code9xs.service.UserService;
import com.code9xs.util.*;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Suhd
 * @date 2021/4/24
 * @time 20:56
 * @wechat i9xswanan
 * @github https://github.com/Code9xs
 */
@Service
@Transactional
public class UserServiceImpl implements UserDetailsService, UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private UserAssociationMapper  userAssociationMapper;

    @Autowired
    private ApplicationMapper applicationMapper;

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private ArticleService articleService;

    @Autowired
    private MailClient mailClient;

    @Autowired
    private ToDoMapper toDoMapper;

    @Autowired
    private AssociationMapper associationMapper;

    @Autowired
    private AssociationService associationService;



    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        // 1.通过邮箱查找用户
        User user = userMapper.selectUserByMail(s);
        if (user == null){
            throw new UsernameNotFoundException("用户账号未找到");
        }
        // 2.通过用户主键查找用户权限
        List<GrantedAuthority> authority = getUserAuthority(user.getId());
        return new AccountUser(user.getId(),user.getUsername(),user.getPassword(),authority,user.getEmail());
    }

    public String getUserAuthorityInfo(Integer userId){
        String authority = "";
        User sysUser = userMapper.selectByPrimaryKey(userId);
        if (redisUtil.hasKey("GrantedAuthority:" + sysUser.getUsername())) {
            authority = (String) redisUtil.get("GrantedAuthority:" + sysUser.getUsername());
        } else {
            List<Map<String,Object>> roles = userMapper.selectRoleByUid(userId);
            if (roles != null){
                authority = roles.stream().map(r -> "ROLE_" + r.get("name")).collect(Collectors.joining(","));
            }
            redisUtil.set("GrantedAuthority:" + sysUser.getUsername(), authority, 3600);
        }
        return authority;
    }


    /**
     * 获取用户权限信息（角色、菜单权限）
     * @param userId
     * @return
     */
    public List<GrantedAuthority> getUserAuthority(Integer userId){
        // 角色(ROLE_admin)、菜单操作权限 sys:user:list
        // ROLE_admin,ROLE_normal,sys:user:list,....
        return AuthorityUtils.commaSeparatedStringToAuthorityList(getUserAuthorityInfo(userId));
    }

    @Override
    public boolean reg(JSONObject param) {
        Integer exist = userMapper.selectUserIsExistByEmail(param.getString("email"));
        if (exist > 0){
            return false;
        }
        // 密码进行加密
        BCryptPasswordEncoder bc = new BCryptPasswordEncoder();
        String encodePassword = bc.encode(param.getString("password"));
        User regUser = new User(IDPoolUtil.getUID(),
                param.getString("username"),
                param.getString("gender"),
                param.getString("studentNo"),
                param.getInteger("age"),
                encodePassword,
                param.getString("phone"),
                param.getString("email"),
                param.getString("avatar"));
        userMapper.insertSelective(regUser);
        // 给用户授予四级用户权限
        userRoleMapper.insertUserRole(regUser.getId(),7);
        return true;
    }

    @Override
    public boolean joinAssociation(JSONObject param) {
        User currentUser = getCurrentUser();
        // 判断当前用户是否已经在本社团
        int isExistAssociation = userAssociationMapper.selectUserIsExistAssociation(param.getInteger("uid"), param.getInteger("uid"));
        if (isExistAssociation > 0){
            return false;
        }
        // 提交申请
        Application application = new Application();
        application.setUid(currentUser.getId());
        application.setAid(param.getInteger("aid"));
        application.setReason(param.getString("reason"));
        application.setTime(DateUtils.getCurrentTime());
        application.setStatus("已提交申请");
        application.setId(IDPoolUtil.getOtherID());
        applicationMapper.insertSelective(application);
        return true;
    }



    public User getCurrentUser(){
        String name = SecurityContextHolder.getContext().getAuthentication().getName();
        return userMapper.selectUserByUsername(name);
    }

    @Override
    public Map<String, Object> getUserPersonalCenter() {
        Map<String,Object> data = articleService.getUserInfoBar();
        User currentUser = getCurrentUser();
        data.put("gender",currentUser.getGender());
        data.put("email",currentUser.getEmail());
        data.put("phone",currentUser.getPhone());
        int commentCount = articleMapper.selectCommentCountByUid((Integer) data.get("id"));
        data.put("comment",commentCount);

        return data;
    }

    @Override
    public boolean updateUserInfo(User user) {
        int flag = userMapper.updateByPrimaryKeySelective(user);
        if (flag > 0){
            return true;
        }
        return false;
    }

    @Override
    public String getMailCheckCode() {
        final String checkCode = CheckCodeUtil.getCheckCode();
        final String key = UUIDGenerator.get16UUID();
        redisUtil.set(key,checkCode,360);
        mailClient.sendMail(getCurrentUser().getEmail(),"验证码","你的修改邮箱验证码为：" + checkCode + "，有效期为 6 分钟！");
        return key;
    }

    @Override
    public Result modifyPassword(String newPassword, String key, String checkCoke) {
        String tureCode = (String)redisUtil.get(key);
        long expire = redisUtil.getExpire(key);
        if (!(expire > 0)){
            return Result.fail(HttpServletResponse.SC_FORBIDDEN,"修改失败，验证码已到期！",null);
        }
        if (!checkCoke.equals(tureCode)){
            return Result.fail(HttpServletResponse.SC_OK,"修改失败，验证码错误！",null);
        }
        BCryptPasswordEncoder bc = new BCryptPasswordEncoder();
        String encode = bc.encode(newPassword);
        User user = new User();
        user.setId(getCurrentUser().getId());
        user.setPassword(encode);
        userMapper.updateByPrimaryKeySelective(user);
        return Result.fail(HttpServletResponse.SC_OK,"修改成功，请重新登录！",null);
    }

    @Override
    public List<Map<String,Object>> getCurrentUserRoles() {
        return userMapper.selectRoleByUid(getCurrentUser().getId());
    }

    @Override
    public PageUtil getUserTodo(Integer page,Integer pageSize) {
        PageUtil pageUtil = new PageUtil();
        int total = toDoMapper.selectAllCountByUid();
        pageUtil.setTotal(total);
        pageUtil.setPageSize(pageSize);
        pageUtil.setPage(page);
        List<Map<String, Object>> maps = toDoMapper.selectAllToDoPagination(pageUtil.getStartTotal() - 1, pageSize);
        List<Map<String,Object>> data = new ArrayList<>();
        maps.forEach(v -> {
            String type = (String)v.get("type");
            if (type.equals("创建社团申请")){
                Integer aid = (Integer) v.get("event_id");
                final Map<String, Object> associationInfo = associationService.getAssociationInfo(aid);
                List<Title> titles = associationService.getAssociationTitle(aid);
                List<AssociationDepartment> departments = associationService.getAssociationDepartment(aid);
                associationInfo.put("titles",titles);
                associationInfo.put("departments",departments);
                data.add(associationInfo);
            }
        });
        pageUtil.setData(data);
        return pageUtil;
    }

    @Override
    public int getAllToDoCount() {
        return toDoMapper.selectAllCountByUid();
    }

    //    public void clearUserAuthorityInfo(String username) {
//        redisUtil.del("GrantedAuthority:" + username);
//    }

//    public void clearUserAuthorityInfoByRoleId(Integer roleId) {
//
//        List<User> users = userMapper.selectUserByRoleId(roleId);
//
//        users.forEach(u -> {
//            this.clearUserAuthorityInfo(u.getUsername());
//        });
//
//    }

}
